package com.jl15988.simpletools.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jl15988.simpletools.common.exception.BusinessException;
import com.jl15988.simpletools.common.security.JwtTokenUtil;
import com.jl15988.simpletools.system.constant.MenuConstant;
import com.jl15988.simpletools.system.constant.UserConstant;
import com.jl15988.simpletools.system.domain.dto.MenuDTO;
import com.jl15988.simpletools.system.domain.dto.UserLoginDTO;
import com.jl15988.simpletools.system.domain.dto.UserRegisterDTO;
import com.jl15988.simpletools.system.domain.dto.UserUpdateDTO;
import com.jl15988.simpletools.system.domain.entity.Menu;
import com.jl15988.simpletools.system.domain.entity.User;
import com.jl15988.simpletools.system.domain.vo.LoginResult;
import com.jl15988.simpletools.system.domain.vo.LoginUserVO;
import com.jl15988.simpletools.system.mapper.MenuMapper;
import com.jl15988.simpletools.system.mapper.UserMapper;
import com.jl15988.simpletools.system.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户服务实现类
 *
 * @author jl15988
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Autowired
    private MenuMapper menuMapper;

    @Override
    public LoginResult login(UserLoginDTO loginDTO) {
        // 进行身份验证
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                loginDTO.getUsername(), loginDTO.getPassword());
        Authentication authentication = authenticationManager.authenticate(authenticationToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);

        // 生成JWT令牌
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        String token = jwtTokenUtil.generateToken(userDetails);

        // 获取用户信息
        User user = this.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, loginDTO.getUsername()));
        // 清除敏感信息
        user.setPassword(null);
        LoginUserVO userVO = BeanUtil.toBean(user, LoginUserVO.class);

        // 返回结果
        return LoginResult.builder()
                .token(token)
                .user(userVO)
                .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean register(UserRegisterDTO registerDTO) {
        // 验证两次密码是否一致
        if (!registerDTO.getPassword().equals(registerDTO.getConfirmPassword())) {
            throw new BusinessException("两次输入的密码不一致");
        }

        // 验证用户名是否已存在
        long count = this.count(new LambdaQueryWrapper<User>().eq(User::getUsername, registerDTO.getUsername()));
        if (count > 0) {
            throw new BusinessException("用户名已存在");
        }

        // 创建用户
        User user = new User();
        user.setUsername(registerDTO.getUsername());
        user.setPassword(passwordEncoder.encode(registerDTO.getPassword()));
        user.setRole(registerDTO.getApplyAsDeveloper() ? UserConstant.ROLE_DEVELOPER : UserConstant.ROLE_USER);
        user.setAvatar(UserConstant.DEFAULT_AVATAR);
        user.setCreatedAt(LocalDateTime.now());

        return this.save(user);
    }

    @Override
    public User getCurrentUser() {
        // 获取当前登录用户名
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String username = authentication.getName();

        // 查询用户信息
        User user = this.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        if (user != null) {
            // 清除敏感信息
            user.setPassword(null);
        }
        return user;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateUserInfo(UserUpdateDTO updateDTO) {
        // 获取当前登录用户
        User currentUser = this.getCurrentUser();
        if (currentUser == null) {
            throw new BusinessException("用户未登录");
        }

        // 只能更新自己的信息
        if (!currentUser.getId().equals(updateDTO.getId())) {
            throw new BusinessException("只能更新自己的信息");
        }

        // 更新用户信息
        User user = new User();
        user.setId(updateDTO.getId());
        if (StrUtil.isNotBlank(updateDTO.getAvatar())) {
            user.setAvatar(updateDTO.getAvatar());
        }
        if (updateDTO.getDevProfile() != null && !updateDTO.getDevProfile().isEmpty()) {
            // 只有开发者才能更新开发者信息
            if (currentUser.getRole() != UserConstant.ROLE_DEVELOPER && currentUser.getRole() != UserConstant.ROLE_ADMIN) {
                throw new BusinessException("非开发者不能更新开发者信息");
            }
            user.setDevProfile(updateDTO.getDevProfile());
        }

        return this.updateById(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changePassword(String oldPassword, String newPassword) {
        // 获取当前登录用户
        User currentUser = this.getCurrentUser();
        if (currentUser == null) {
            throw new BusinessException("用户未登录");
        }

        // 查询用户完整信息（包含密码）
        User user = this.getById(currentUser.getId());

        // 验证旧密码
        if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
            throw new BusinessException("旧密码不正确");
        }

        // 更新密码
        user.setPassword(passwordEncoder.encode(newPassword));
        return this.updateById(user);
    }

    @Override
    public IPage<User> getUserPage(int page, int size, String username, Integer role) {
        // 构建查询条件
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(username)) {
            queryWrapper.like(User::getUsername, username);
        }
        if (role != null) {
            queryWrapper.eq(User::getRole, role);
        }

        // 分页查询
        Page<User> pageParam = new Page<>(page, size);
        IPage<User> pageResult = this.page(pageParam, queryWrapper);

        // 清除敏感信息
        pageResult.getRecords().forEach(user -> user.setPassword(null));

        return pageResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateUserRole(Long userId, Integer role) {
        // 验证角色值是否合法
        if (role != UserConstant.ROLE_USER && role != UserConstant.ROLE_DEVELOPER && role != UserConstant.ROLE_ADMIN) {
            throw new BusinessException("角色值不合法");
        }

        // 验证用户是否存在
        User user = this.getById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        // 更新角色
        user.setRole(role);
        return this.updateById(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteUser(Long userId) {
        // 验证用户是否存在
        User user = this.getById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        // 不能删除管理员
        if (user.getRole() == UserConstant.ROLE_ADMIN) {
            throw new BusinessException("不能删除管理员");
        }

        return this.removeById(userId);
    }
    
    @Override
    public List<MenuDTO> getUserMenus() {
        // 获取当前登录用户
        User currentUser = this.getCurrentUser();
        if (currentUser == null) {
            throw new BusinessException("用户未登录");
        }

        // 根据用户角色获取菜单列表
        List<Menu> menuList = menuMapper.selectMenusByRoleId(currentUser.getRole());
        
        // 过滤掉按钮类型的菜单，只保留目录和菜单类型
        menuList = menuList.stream()
                .filter(menu -> menu.getType() == MenuConstant.TYPE_DIRECTORY || menu.getType() == MenuConstant.TYPE_MENU)
                .filter(menu -> menu.getVisible() == MenuConstant.VISIBLE_SHOW)
                .collect(Collectors.toList());
        
        // 转换为DTO
        List<MenuDTO> menuDTOList = menuList.stream().map(menu -> {
            MenuDTO dto = new MenuDTO();
            BeanUtils.copyProperties(menu, dto);
            return dto;
        }).collect(Collectors.toList());
        
        // 构建菜单树
        return buildMenuTree(menuDTOList);
    }
    
    /**
     * 构建菜单树
     *
     * @param menuList 菜单列表
     * @return 菜单树
     */
    private List<MenuDTO> buildMenuTree(List<MenuDTO> menuList) {
        // 按照父级ID分组
        Map<Long, List<MenuDTO>> parentMap = menuList.stream()
                .collect(Collectors.groupingBy(MenuDTO::getParentId));

        // 获取顶级菜单
        List<MenuDTO> rootMenus = parentMap.getOrDefault(0L, new ArrayList<>());

        // 递归设置子菜单
        rootMenus.forEach(menu -> setChildren(menu, parentMap));

        return rootMenus;
    }

    /**
     * 递归设置子菜单
     *
     * @param menu 当前菜单
     * @param parentMap 父级菜单映射
     */
    private void setChildren(MenuDTO menu, Map<Long, List<MenuDTO>> parentMap) {
        List<MenuDTO> children = parentMap.getOrDefault(menu.getId(), new ArrayList<>());
        menu.setChildren(children);
        children.forEach(child -> setChildren(child, parentMap));
    }
} 